/*******************************************************************************
 * file  : memory block alloc
 * creat : apleilx
 * data  : 2022/08/25
 *******************************************************************************/

#ifndef __mem_block_alloc__
#define __mem_block_alloc__

#include "mytype.h"
#include "sys_init.h"

#ifdef __cplusplus
extern "C"
{
#endif

	/*******************************************************************************
	 * @brief  内存块管理数据结构
	 *
	 *******************************************************************************/
	struct mem_block_info_str
	{
		uu16 used;
		uu16 used_max;
	};

	struct mem_block_cfg_str
	{
		uu16 block_size;				 // 块尺寸 // 大于1且为8的倍数
		uu16 block_num;					 // 块数量 // 1~65535
		void *mem_base;					 // 内存基址, 8字节对齐
		uu16 *mem_mark;					 // 使用标记
		struct mem_block_info_str *info; //信息
	};

	struct mem_block_ext_cfg_str
	{
		const struct mem_block_cfg_str *const *cfg;
		void (*init)(void);
		void *(*malloc)(uu32 size);
		void (*free)(void *);
		uu16 (*lock)(void);
		void (*unlock)(void);
	};

	typedef struct mem_block_info_str mem_block_info_type;
	typedef const struct mem_block_cfg_str mem_block_cfg_type;
	typedef const struct mem_block_ext_cfg_str mem_block_ext_cfg_type;

//##############################################################################
//##############################################################################
/*******************************************************************************
 * @brief  定义内存块列表
 * 		   块尺寸从大到小排列，首个next为0
 *******************************************************************************/
// 创建列表指针首尾
#define mem_blk_gen(name)                                    \
	OBJ_USED OBJ_SECTION("BLK_MEM_SEC_" #name "_1_")         \
		mem_block_cfg_type *const memblk_##name##_start = 0; \
	OBJ_USED OBJ_SECTION("BLK_MEM_SEC_" #name "_3_")         \
		mem_block_cfg_type *const memblk_##name##_end = 0

/*******************************************************************************
 * @brief  添加内存块到列表，常规数组方式
 * \param[in] name 内存块表名字
 * \param[in] size 单块尺寸
 * \param[in] n    块数量
 * \param[in] pos  多个表排列位置，字符顺序应和size顺序一致
 * \retval: 无
 *******************************************************************************/
#define mem_blk_add(name, size, n, pos)                           \
	static mem_block_info_type memblk_##name##size##_info = {0};  \
	static uu64 memblk_##name##size##_base[n][size / 8];          \
	static uu16 memblk_##name##size##_mark[(n + 15) >> 4];        \
	static mem_block_cfg_type memblk_##name##size##_cfg = {       \
		size,                                                     \
		n,                                                        \
		memblk_##name##size##_base,                               \
		memblk_##name##size##_mark,                               \
		&memblk_##name##size##_info,                              \
	};                                                            \
	OBJ_USED OBJ_SECTION("BLK_MEM_SEC_" #name "_2_" #pos)         \
		mem_block_cfg_type *const memblk_##name##size##_cfg_ptr = \
			&memblk_##name##size##_cfg

/*******************************************************************************
 * @brief  添加内存块到列表，数组+SECTION方式
 * \param[in] name 内存块表名字
 * \param[in] size 单块尺寸
 * \param[in] n    块数量
 * \param[in] pos  多个表排列位置，字符顺序应和size顺序一致
 * \param[in] sec  内存块所在 SECTION
 * \retval: 无
 *******************************************************************************/
#define mem_blk_add_sec(name, size, n, pos, sec)                  \
	static mem_block_info_type memblk_##name##size##_info = {0};  \
	OBJ_SECTION(sec)                                              \
	static uu64 memblk_##name##size##_base[n][size / 8];          \
	static uu16 memblk_##name##size##_mark[(n + 15) >> 4];        \
	static mem_block_cfg_type memblk_##name##size##_cfg = {       \
		size,                                                     \
		n,                                                        \
		memblk_##name##size##_base,                               \
		memblk_##name##size##_mark,                               \
		&memblk_##name##size##_info,                              \
	};                                                            \
	OBJ_USED OBJ_SECTION("BLK_MEM_SEC_" #name "_2_" #pos)         \
		mem_block_cfg_type *const memblk_##name##size##_cfg_ptr = \
			&memblk_##name##size##_cfg

/*******************************************************************************
 * @brief  添加内存块到列表，内存地址方式
 * \param[in] name 内存块表名字
 * \param[in] size 单块尺寸
 * \param[in] n    块数量
 * \param[in] pos  多个表排列位置，字符顺序应和size顺序一致
 * \param[in] addr 内存块所在地址
 * \retval: 无
 *******************************************************************************/
#define mem_blk_add_addr(name, size, n, pos, addr)                \
	static mem_block_info_type memblk_##name##size##_info = {0};  \
	static uu16 memblk_##name##size##_mark[(n + 15) >> 4];        \
	static mem_block_cfg_type memblk_##name##size##_cfg = {       \
		size,                                                     \
		n,                                                        \
		(void *)(addr),                                           \
		memblk_##name##size##_mark,                               \
		&memblk_##name##size##_info,                              \
	};                                                            \
	OBJ_USED OBJ_SECTION("BLK_MEM_SEC_" #name "_2_" #pos)         \
		mem_block_cfg_type *const memblk_##name##size##_cfg_ptr = \
			&memblk_##name##size##_cfg

/*******************************************************************************
 * @brief  获取变量名
 * \retval: 无
 *******************************************************************************/
#define mem_blk_cfg_name(name) (&memblk_##name##_start)
#define mem_blk_ext_cfg_name(name) (&name)

//##############################################################################
//##############################################################################
/*******************************************************************************
 * @brief  接口功能定义
 * \param[in] name 内存块表名字
 * \param[in] lock 多任务系统中，互斥锁申请
 * \param[in] unlock 多任务系统中，互斥锁释放
 * \retval: 无
 *******************************************************************************/
#define mem_blk_ext_cfg_make(name, lock, unlock) \
	extern mem_block_ext_cfg_type name;          \
	void mem_blk_fun_##name##init(void)          \
	{                                            \
		mem_blk_ext_init(&name);                 \
	}                                            \
	void *mem_blk_fun_##name##malloc(uu32 size)  \
	{                                            \
		return mem_blk_ext_malloc(&name, size);  \
	}                                            \
	void mem_blk_fun_##name##free(void *p)       \
	{                                            \
		mem_blk_ext_free(&name, p);              \
	}                                            \
	OBJ_USED mem_block_ext_cfg_type name = {     \
		&(memblk_##name##_start),                \
		mem_blk_fun_##name##init,                \
		mem_blk_fun_##name##malloc,              \
		mem_blk_fun_##name##free,                \
		lock,                                    \
		unlock}

	//##############################################################################
	//##############################################################################
	/*******************************************************************************
	 * @brief  内存块信息初始化
	 * \param[in] cfg
	 * \retval: none
	 *******************************************************************************/
	void mem_blk_init(mem_block_cfg_type *const *cfg);

	/*******************************************************************************
	 * @brief  申请内存块
	 * \param[in] cfg
	 * \param[in] size
	 * \retval: 目标地址指针。0指示申请失败-申请尺寸大于列表最大块尺寸或者无可用块
	 *******************************************************************************/
	void *mem_blk_malloc(mem_block_cfg_type *const *cfg, uu32 size);

	/*******************************************************************************
	 * @brief  释放内存块
	 * \param[in] cfg
	 * \param[in] p 数据位置
	 * \retval: none
	 *******************************************************************************/
	void mem_blk_free(mem_block_cfg_type *const *cfg, void *p);

	/*******************************************************************************
	 * @brief  内存块信息初始化
	 * \param[in] cfg
	 * \retval: none
	 *******************************************************************************/
	void mem_blk_ext_init(mem_block_ext_cfg_type *cfg);

	/*******************************************************************************
	 * @brief  申请内存块
	 * \param[in] cfg
	 * \param[in] size
	 * \retval: 目标地址指针。0指示申请失败-申请尺寸大于列表最大块尺寸或者无可用块
	 *******************************************************************************/
	void *mem_blk_ext_malloc(mem_block_ext_cfg_type *cfg, uu32 size);

	/*******************************************************************************
	 * @brief  释放内存块
	 * \param[in] cfg
	 * \param[in] p 数据位置
	 * \retval: none
	 *******************************************************************************/
	void mem_blk_ext_free(mem_block_ext_cfg_type *cfg, void *p);

#ifdef __cplusplus
}
#endif
/*******************************************************************************
 * EOF
 *******************************************************************************/
#endif // __mem_block_alloc__
